#include <linux/module.h>
#include <asm/pgtable.h>
#include <linux/version.h>
#include <asm/page.h>
#include <linux/gfp.h>
#include <linux/page-flags.h>
#include <linux/sched.h>//find_task_by_vpid
#include <linux/mm.h>//find_vma

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("CONVERT USER VIRTUAL ADDRESS TO PHYADDRESS");

static int pid;
static unsigned long va;

module_param(pid,int,0644);
module_param(va,ulong,0644);

static int find_pgd_init(void)
{
    	unsigned long pa=0;
    	struct task_struct *pcb_tmp=NULL;
    	pgd_t *pgd_tmp=NULL;
    	pud_t *pud_tmp=NULL;
    	pmd_t *pmd_tmp=NULL;
    	pte_t *pte_tmp=NULL;

    	printk(KERN_ALERT "test:va=0x%lx,pid=%d.\n",va,pid);

    	rcu_read_lock();
    	if( !( pcb_tmp = pid_task(find_vpid(pid), PIDTYPE_PID) ) ) 
    	{
        	rcu_read_unlock();
        	printk(KERN_ALERT "Can't find the task %d.\n",pid);
        	return 0;
    	}
    	rcu_read_unlock();

	printk("The page index_table address = 0x%p\n\n",pcb_tmp->mm->pgd);
    
    	printk(KERN_ALERT "pgd=0x%p\n",pcb_tmp->mm->pgd);
    	if(!find_vma(pcb_tmp->mm,va))
    	{
        	printk(KERN_ALERT "virt_addr 0x%lx not available.\n",va);
        	return 0;
    	}
    	pgd_tmp=pgd_offset(pcb_tmp->mm,va);
    	printk(KERN_ALERT "pgd_tmp=0x%p\n",pgd_tmp);
    	printk(KERN_ALERT "pgd_val(*pgd_tmp)=0x%lx\n\n",pgd_val(*pgd_tmp));
   	 if(pgd_none(*pgd_tmp))
    	{
     	   printk(KERN_ALERT "Not mapped in pgd.\n");
     	   return 0;
    	}

    	pud_tmp=pud_offset(pgd_tmp,va);
    	pmd_tmp=pmd_offset(pud_tmp,va);


    	pte_tmp=pte_offset_kernel(pmd_tmp,va);
    	if(pte_none(*pte_tmp))
    	{
        	printk(KERN_ALERT "Not mapped in pte.\n");
        	return 0;
    	}
    	if(!pte_present(*pte_tmp))
    	{
   	     	printk(KERN_ALERT "pte not in RAM,maybe swaped.\n");
    	    	return 0;
    	}
    	pa=(pte_val(*pte_tmp)&PAGE_MASK)|(va&~PAGE_MASK);
    	printk(KERN_ALERT "Virtual address: 0x%lx in RAM is 0x%lx.\n",va,pa);
    	printk(KERN_ALERT "Part content in 0x%lx is 0x%lx.\n",pa,*(unsigned long*)((char *)pa+PAGE_OFFSET));
	int i;
	printk("some content:\n");
	for(i=0;i<40;i=i+4)
	{
		printk("%lx\n",*(unsigned long*)((char*)pa+PAGE_OFFSET+i));
	}	
    return 0;
}

static void find_pgd_exit(void)
{
    	printk(KERN_ALERT "Goodbye.\n");
}

module_init(find_pgd_init);
module_exit(find_pgd_exit);

MODULE_LICENSE("GPL");

MODULE_AUTHOR("Why");

MODULE_DESCRIPTION("GET WESSAGE");
